home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1997 December
/
EnigmA AMIGA RUN 23 (1997)(G.R. Edizioni)(IT)[!][issue 1997-12][EAR-CD VII].iso
/
listati
/
readiff.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-11
|
19KB
|
435 lines
//**********************************************************************
//* *
//* Algoritmo per la decodifica di immagini IFF-ILBM *
//* *
//**********************************************************************
#include <exec/memory.h>
#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#define LIB_VERSION 39
#define DIM_MSG 20
#define NUM_MSG 10
#define DIM_RICERCA 2000
#define PUB_PULITA MEMF_PUBLIC|MEMF_CLEAR
#define ERR_MEMORIA 1
#define ERR_LIBS 2
#define ERR_TIPO_FILE 3
#define ID_IFF_FORM 0x464F524D //id header IFF (parola "FORM")
#define ID_IFF_ILBM 0x494C424D //id iff (parola "ILBM")
#define ID_IFF_BMHD 0x424D4844 //id IFF (parola "BMHD")
#define ID_IFF_CMAP 0x434D4150 //id iff (parola "CMAP")
#define ID_IFF_CAMG 0x43414D47 //id IFF (parola "CAMG")
#define ID_IFF_BODY 0x424F4459 //id iff (parola "BODY")
struct chunk {
ULONG id;
ULONG dimens;
UBYTE *buffer;
};// CMAP CAMG e BODY hanno praticamente la stessa struttura
struct chunk_bmhd {
ULONG id;
ULONG dimens;
UWORD lx_immagine;
UWORD ly_immagine;
UWORD x_bitmap;
UWORD y_bitmap;
UBYTE piani;
UBYTE decodifica;
UBYTE compressione;
UWORD colore_trasparente;
UBYTE x_aspetto_pixel;
UBYTE y_aspetto_pixel;
UWORD lx_schermo;
UWORD ly_schermo;
};
struct Library *intuibase=NULL,
*gfxbase=NULL;
struct chunk *cmap=NULL,
*camg=NULL,
*body=NULL;
struct chunk_bmhd bmhd; //BMHD ha grandezza fissa
// ########## dichiarazioni delle funzioni C usate #################
void Dealloca_Buffers();
oULONG Find_Id (ULONG,UBYTE*,ULONG);
struct chunk* File_To_Buffer(FILE*,ULONG,UBYTE*,ULONG);
int DecodeIff(FILE*);
void CloseLibs();
// ########## inizio listato ######################################
int main (int argc,char **argv)
{
FILE* finput = NULL;
int numero_files=1;
if ((intuibase=(struct Library*)OpenLibrary("intuition.library",LIB_VERSION))==NULL) return (ERR_LIBS);
// struct Library* Openlibrary(char* nome,ULONG versione); (LIBRERIA EXEC)
// La funzione OpenLibrary apre una libreria di sistema.
// Accetta come argomenti il nome della libreria da aprire ("nome") e la versione
// della stessa ("versione").
// in caso di riuscita apertura della lireria restituisce l'indirizzo
// della struttura libreria appena allocata,viceversa 0 (NULL).
if ((gfxbase =(struct Library*)OpenLibrary("graphics.library",LIB_VERSION))==NULL)
{
CloseLibrary(intuibase);
return (ERR_LIBS);
}
for (numero_files=1;numero_files < argc;numero_files++)
if ((finput = fopen(argv[numero_files],"r")))
// FILE* fopen(char* nome,char* modo); (PORTABILITA' ANSI C)
// fopen apre un file. come primo argomento accetta un char* che
// rappresenta il percorso e il nome del del file nel disco (es. "ram:t/pippo.txt")
// mentre come secondo un char* che rappresenta il modo di accesso.
// I principali modi di accesso sono:
// "r" ,file a sola lettura
// "w" ,file a sola scrittura(se non esise viene creato)
// "a" ,file attaccabile(cioè se il file esiste allora la funzione
// restituirà un puntatore alla fine del file in modo da poter
// andare a vanti con la scrittura).
// Le opzioni sono combinabili tra loro quindi datevi un'occhiata ai docs
// per maggiori delucidazioni o se avete qualche esigenza speciale.
// Se il file non esiste allora se come modo d'accesso abbiamo inserito
// "r" verrà restituito NULL, altrimenti verrà creato un nuovo file e
// verrà restituito un FILE*.
{
rewind ( finput );
// void rewind(FILE* file); (PORTABILITA' ANSI C)
// rewind porta il azzera il puntatore del file, cioè lo fa puntare
// all'inizio dell'archivio.
DecodeIff ( finput );
fclose ( finput );
// void fclose(FILE* file);(PORTABILITA' ANSI C)
// fclose chiude il file. Tutto qui!
}
if (intuibase) CloseLibrary (intuibase);
// void CloseLibrary(struct Library* libreria); (Libreria EXEC)
// Dovrei forse dirvi a cosa serve questa funzione?
if (gfxbase) CloseLibrary (gfxbase);
return(0);
}
void Dealloca_Buffers()
// Questa funzione dealloca i buffer puntati dalle nostre varibili globali,
// e successivamente dealloca le strutture chunk.
{
if (cmap->buffer) FreeMem(cmap->buffer,cmap->dimens);
// void FreeMem(APTR ptr_memoria,ULONG dimensione) (libreria EXEC)
// FreeMem libera una quantità di bytes a partire dalla locazione puntata
// dall' APTR per un totale di bytes memorizzato in "dimensione"
if (camg->buffer) FreeMem(camg->buffer,camg->dimens);
if (body->buffer) FreeMem(body->buffer,body->dimens);
if (cmap) FreeMem(cmap,sizeof(struct chunk));
if (camg) FreeMem(camg,sizeof(struct chunk));
if (body) FreeMem(body,sizeof(struct chunk));
cmap=NULL;camg=NULL;body=NULL;
}
ULONG Find_Id(ULONG id, UBYTE* buffer,ULONG dimens_buffer)
// Questa funzione permette di cercare l'header in un buffer in memoria.
// "carattere" contiene la prima "lettera" che compone l'ID.
// Il resto del codice è una normale ricerca sequenziale.
// La funzione ritorna la posizione del chunk nel buffer (e quindi nel
// file) in caso di successo e il valore -1 in caso di insuccesso.
{
ULONG posiz=0;
UBYTE trovato=0;
UBYTE carattere=UBYTE(id>>24);
ULONG* indice=(ULONG*)buffer;
while ((posiz < dimens_buffer) & (!trovato))
{
if (carattere == (*indice>>24)) if (*indice == id) trovato=1;
((UBYTE*)indice)++;
if (!trovato) posiz++;
}
if (trovato) return(posiz);
return(-1);
}
struct chunk* File_To_Buffer(FILE *finput,ULONG id,UBYTE* buffer,ULONG dimens)
// Questa funzione crea il chunk vero e proprio trasferendo i dati dal
// file in memoria. La funzione ritorna il PUNTATORE alla struttura
// chunk in caso di successo, 0 (NULL) altrimenti.
{
struct chunk *appo=NULL;
ULONG posizione_id=0;
if ((appo=AllocMem(sizeof(struct chunk),MEMF_PUBLIC))==NULL) return(0);
// APTR AllocMem(ULONG dimensione,ULONG tipo_memoria); (libreria EXEC)
// AllocMem alloca una quantità di bytes pari al valore della prima ULONG
// nel tipo di memoria specificato dalla seconda.
// i tipi di memoria possono essere:
// "MEMF_CHIP" (alloca nella chip ram)
// "MEMF_FAST" (alloca nella fast ram)
// "MEMF_PUBLIC" (alloca nella memoria pubblica,cioè memoria di solito
// usata per allocare task interrupt o qualcos'altro).
// "MEMF_CLEAR" (i bytes allocati vengono azzerati).
// I tipi possono essere "mescolati" tra loro (cioè si puo' fare
// AllocMem(pippo, MEMF_PUBLIC | MEMF_CLEAR );
posizione_id = Find_Id(id,buffer,dimens);
if (posizione_id == (-1)) goto errore_fatale;
fseek(finput,posizione_id,SEEK_SET);
// int fseek(FILE* file,long posizione,int tipo_spostamento) (PORTABILITA' ANSI C)
// fseek sposta il puntatore al FILE* di tot bytes (avanti o indietro)
// indicati nel valore della long.int specifica da che punto spostarsi
// int = SEEK_SET impone al file di spostarsi di tot bytes dall'inizio del file
// int = SEEK_CUR dalla posizione corrente del puntatore
// int = SEEK_END dalla fine del file.
// se lo spostamento ha successo la funzione restituisce il valore 0
// un qualsiasi altro valore altrimenti.
fread((char*)&appo->id,1,4,finput);
// long fread(void* buffer,long dim_blocco,long num_blocchi,FILE* file) (PORTABILITA' ANSI C)
// la funzione fread legge da un FILE* un certo numero di blocchi indicato
// nella seconda long,dove ogni blocco è definito in dimensioni
// dalla prima long,e trasferisce i bytes letti in un vettore.
// Il trasferimento avviene dalla posizione puntata dal FILE* e alla fine
// della funzione il FILE* punterà blocco successivo dell'ultimo blocco letto.
// La funzione restituisce il numero di blocchi effettivamente letti dal
// file (in pratica serve a segnalare se arriviamo alla fine del file
// oppure se c'e' stato qualche errore).
//
// es: Nel programma utilizziamo fread((char*)&appo->id,1,4,finput);
// ciò significa che:
// "(char*)&appo->id" è il vettore dove andranno trasferiti i bytes letti
// "1" è la dimensione in bytes dei blocchi da trasferire
// (se fosse stata "2" allora avremmo trasferito una WORD alla volta,
// "4" una LONG e "size_of(struct chunk_bmhd)" un numero
// di bytes pari a quelli usati per definire la struttura
// chunk bmhd, ecc).
// "4" è il numero di blocchi da leggere (in questo caso 4 bytes,
// o meglio, 4 char(anche se in pratica non cambia nulla)).
// "finput" è il puntatore al file.
fread((char*)&appo->dimens,1,4,finput);
if ((appo->buffer=AllocMem(appo->dimens,MEMF_PUBLIC))==NULL) goto errore_fatale;
fread((char*)appo->buffer,1,appo->dimens,finput);
return(appo);
errore_fatale: // La memoria è finita! Andate in pace.
FreeMem(appo,sizeof(struct chunk));
return(0);
}
int DecodeIff(FILE* finput)
{
struct Screen *schermo=NULL;
struct Window *finestra1=NULL,
*finestra2=NULL;
struct BitMap immagine;
ULONG i=0,j=0,r=0,g=0,b=0,riga=0;
UBYTE cicli=0,numero_bytes=0,bytes_per_riga=0,num_piano=0;
UBYTE* buffer=NULL;
UBYTE* appo=NULL;
UBYTE* indirizzo=NULL;
ULONG general=0;
ULONG dimens_buffer=DIM_RICERCA;
ULONG* camg_data=NULL;
fread ((char*)&general,1,4,finput);
// nota per fread: avremmo pututo scrivere anche fread(&general,4,1,finput)
// e non sarebbe cambiato nulla!
if (general != ID_IFF_FORM) return(-2);
fread ((char*)&general,1,4,finput);
if (general<dimens_buffer) dimens_buffer=general-4;
if ((buffer=AllocMem(dimens_buffer,MEMF_PUBLIC))==NULL) return(-3);
fread ((char*)&general,1,4,finput);
if (general != ID_IFF_ILBM) return(-4);
rewind (finput);
fread (buffer,1,dimens_buffer,finput);
general=Find_Id(ID_IFF_BMHD,buffer,dimens_buffer);
if (general == -1 )
{ FreeMem(buffer,dimens_buffer);
return(ERR_TIPO_FILE);
}
fseek(finput,general,SEEK_SET);
fread((char *)&bmhd,1,sizeof(struct chunk_bmhd),finput);
cmap=File_To_Buffer(finput,ID_IFF_CMAP,buffer,dimens_buffer);
camg=File_To_Buffer(finput,ID_IFF_CAMG,buffer,dimens_buffer);
body=File_To_Buffer(finput,ID_IFF_BODY,buffer,dimens_buffer);
if ((cmap)&&(body)&&(camg))
{ if (bmhd.decodifica==1) goto errore_2;
if (bmhd.compressione>1) goto errore_2;
while((bmhd.lx_immagine % 16)) bmhd.lx_immagine++;
InitBitMap(&immagine,bmhd.piani,bmhd.lx_immagine,bmhd.ly_immagine);
// void InitBimap(struct BitMap* bmp,LONG piani,LONG x,LONG y); (libreria graphics)
// inizializza una struttura BitMap(che dovete avere già allocato in
// memoria,occhio!).
// bmp punta alla struttura bitmap
// piani è il numero di bitplanes
// x,y è la lunghezza e l'altezza in pixel dell'immagine da allocare.
for (i=0; i<bmhd.piani; i++)
if ((immagine.Planes[i]=AllocRaster(bmhd.lx_immagine,bmhd.ly_immagine))==NULL)
// PLANEPTR AllocRaster(ULONG x,ULONG y)
// AllocRaster alloca in CHIP ram un bitplane!
// x,y sono la lunghezza e l'altezza in pixel dell'immagine
// AllocRaster restituisce il puntatore al bitplane allocato in caso
// di successo, 0 altrimenti!
// Nota:AllocRaster converte il valore "x" al multiplo di 16 immediatamente
// superiore al valore prefissato.
{ for (j=0;j<i;j++) FreeRaster(immagine.Planes[j],bmhd.lx_immagine,bmhd.ly_immagine);
// Void FreeRaster(PLANEPTR bpl,ULONG x,ULONG y);
// FreeRaster librea il bitplane precedentemente allocato
// bpl è il puntatore al bitplane
// x,y sono la solita lunghezza e altezza del bitplane in pixel.
goto errore_2;
}
camg_data=(ULONG*)camg->buffer;
if ((schermo=(struct Screen*)OpenScreenTags(NULL,
SA_Width,bmhd.lx_schermo, SA_Height,bmhd.ly_schermo,
SA_DisplayID,*camg_data, SA_Depth,bmhd.piani,
SA_FullPalette,TRUE, SA_Title,"IFF Reader V 1.0",
TAG_END,NULL))==NULL) goto errore_3;
// Prendi quattro paghi uno! (neanche al supermercato :-)
// struct Screen* OpenScreenTags(struct NewScreen* dati_schermo,Tag 1,...,Tag n)
// struct Screen* OpenScreenTagList(struct NewScreen* dati_schermo,struct TagItem* taglist)
// struct Window* OpenWindowTags(struct NewWindow* dati_finestra,Tag 1,...,Tag n)
// struct Window* OpenWindowTagList(struct NewWindow* dati_finestra,struct TagItem* taglist)
// (libreria INTUITION)
// Aprono uno schermo (finestra) facendo uso dei Tags.
// I Tags permettono di definire certi tipi di caratteristiche di
// un oggetto senza dover memorizzare tali caratteristiche in una struttura
// dati al momento della creazione dell'oggetto stesso.
// Ad esempio, per arire uno schermo normalmente si definisce prima una struttura
// NewScreen (es.struct NewScreen pippo={0,0,320,200,...} )
// memorizzando all'interno tutti i dati necessari a definire
// lo schermo che verrà aperto con la funzione schermo=Openscreen(&pippo).
// Con i Tags otterremo sempre uno schermo solo che non impazziremo
// nel sistemare al loro giusto posto le variabili nella struttura
// inizializzatrice,settare flags,o perdere tempo in inizializzazioni
// del tipo
// pippo.Width =320;
// pippo.Height=200;
// ecc. ecc.
// Grazie ai Tags potremo definire "al volo" i parametri che più ci interessano
// e in qualsiasi ordine, facendoci risparmiare tempo e fatica!
// Dimenticavo... i tags di immettono nel seguente modo :
// ID_TAG1,valore_tag1,ID_TAG2,valore_tag2,.....,TAG_END,NULL,
// oppure creando una struttura TagItem e definendo i tag nel seg. modo:
// struct TagItem miei_tag_personali={
// {ID_TAG1,valore_tag1},
// {ID_TAG2,valore_tag2},
// {...................},
// {TAG_END,NULL};
//
// OpenScreenTags(...) apre uno schermo con i tags
// OpenScreenTagList(...) apre uno schermo con una TagList precedentemente definita.
// in entrambe le funzioni è possibile definire anche una eventuale
// struttura NewScreen di appoggio
// Le funzioni restituiscono il puntatore della struttura schermo in
// caso di successo,0 (NULL) in caso contrario.
// Se volete saperne di più sui tags andate nella directory di include
// del vostro compilatore C preferito, sotto la directory
// "intuition/screens.h" studiatevi l'interminabile lista di tags
// disponibili (e,dato che ci siete,anche la struttura NewScreen).
// Per OpenWindow... il discorso è uguale, solo che al posto di avere
// La struttura NewScreen abbiamo una struttura NewWindow e i tags
// variano in modo differente.
// Per strudiarvi i Tags delle finestre andate in "intuition/intuition.h"
appo=cmap->buffer;
for(i=0;i<(cmap->dimens/3);i++)
{
r=ULONG(*(appo++));
g=ULONG(*(appo++));
b=ULONG(*(appo++));
r+=r<<8;r+=r<<16;
g+=g<<8;g+=g<<16;
b+=b<<8;b+=b<<16;
SetRGB32(&schermo->ViewPort,i,r,g,b);
// void SetRGB32(struct ViewPort* vp,ULONG,registro,ULONG r,ULONG g,ULONG,b);
// questa funzione setta uno dei registri colore con la quantità
// di rosso,verde,blu (valori ad 8 bit),indicati in "r","g","b".
// L'unica cosa degna di nota è che i valori r,g,b, sono a 32 bit
// e ciascuna componente contenere lo stesso valore del colore
// per tutti e 4 i bytes che compongono la ULONG.
// Es se devo settare r col valore 0x10 allora r dovrà contenere il
// valore 0x10101010, altrimenti la funzione setrgb32 non funzionerà
// correttamente.
}
bytes_per_riga=bmhd.lx_immagine/8;
appo=body->buffer;
for (riga=0;riga<bmhd.ly_immagine;riga++)
{ for(num_piano=0;num_piano<bmhd.piani;num_piano++)
{ indirizzo=immagine.Planes[num_piano]+bytes_per_riga*riga;
if (bmhd.compressione==1)
{ numero_bytes=0;
while (numero_bytes<bytes_per_riga)
{ cicli=UBYTE(*(appo++));
if ((cicli)>127)
{ cicli=(-cicli)+1;
for(i=0;i<cicli;i++,numero_bytes++,indirizzo++) *indirizzo=*appo;
appo++;
}
else for(i=0;i<=cicli;i++,numero_bytes++) *(indirizzo++)=*(appo++);
}
}
else for(i=0;i<bytes_per_riga;i++) *(indirizzo++)=*(appo++);
}
}
if ((finestra2=(struct Window*)OpenWindowTags(NULL,
WA_Left ,0, WA_Top,0,
WA_Width,bmhd.lx_immagine, WA_Height,bmhd.ly_immagine,
WA_SmartRefresh,TRUE, WA_CustomScreen,schermo,
WA_Borderless,TRUE, WA_Title,"IFF Output",
WA_SuperBitMap,&immagine, TAG_END,NULL))==NULL) goto errore_3;
if ((finestra1=(struct Window*)OpenWindowTags(NULL,
WA_Left,0, WA_Top,0,
WA_Width,120, WA_Height,15,
WA_DetailPen,1, WA_BlockPen,0,
WA_IDCMP,IDCMP_CLOSEWINDOW, WA_CustomScreen,schermo,
WA_CloseGadget,TRUE, WA_DragBar,TRUE,
WA_Title,"<- Click ", TAG_END,NULL))==NULL) goto errore_3;
if(finestra1)Wait(1L << finestra1->UserPort->mp_SigBit);
}
errore_3:
if (finestra2) CloseWindow (finestra2);// Prima si chiudono sempre le
if (finestra1) CloseWindow (finestra1);// finestre poi lo schermo, altrimenti
if (schermo) CloseScreen (schermo); // si GURA!
// void CloseWindow(struct Window *finestra_da_chiudere);
// void CloseScreen(struct Screen *schermo_da_chiudere);
// Un giro sulle giostre a chi indovina a cosa servono queste due funzioni!
for (i=0;i<bmhd.piani;i++)// Liberiamo i bitplanes
FreeRaster (immagine.Planes[i],bmhd.lx_immagine,bmhd.ly_immagine);
errore_2:
Dealloca_Buffers();
errore_1:
if (buffer) FreeMem(buffer,dimens_buffer);
return(0);
}